import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:share_fit/app/models/home/heart_rate_model.dart';
import 'package:share_fit/app/tools/color_const.dart';

class HrLineChart extends StatefulWidget {
  final List<HRSummary> summaryList;

  HrLineChart({super.key, List<HRSummary>? summaryList}) : summaryList = summaryList ?? [];

  @override
  State<HrLineChart> createState() => _HrLineChartState();
}

class _HrLineChartState extends State<HrLineChart> {
  List<int> showingTooltipOnSpots = [];

  final List<Color> gradientColors = [Colors.red, Colors.white];
  var titles = <dynamic>{};

  @override
  void didUpdateWidget(HrLineChart oldWidget) {
    super.didUpdateWidget(oldWidget);
    showingTooltipOnSpots.clear();
  }

  @override
  Widget build(BuildContext context) {
    titles = widget.summaryList.map((e) => e.calendar).toSet();

    var lineBarsData = _getLineBarsData();
    final tooltipsOnBar = lineBarsData[0];

    return AspectRatio(
      aspectRatio: 1.70,
      child: Padding(
        padding: EdgeInsets.only(top: 70.h, bottom: 50.h, left: 20.w, right: 60.w),
        child: LineChart(
          LineChartData(
            minY: 0,
            maxY: 200,
            backgroundColor: Colors.white54.withOpacity(.8),
            showingTooltipIndicators: showingTooltipOnSpots.map((index) {
              return ShowingTooltipIndicators([
                LineBarSpot(
                  tooltipsOnBar,
                  lineBarsData.indexOf(tooltipsOnBar),
                  tooltipsOnBar.spots[index],
                ),
              ]);
            }).toList(),
            lineTouchData: lineTouchData,
            gridData: gridData,
            titlesData: titlesData,
            borderData: borderData,
            lineBarsData: lineBarsData,
          ),
        ),
      ),
    );
  }

  get lineTouchData => LineTouchData(
        enabled: true,
        getTouchLineEnd: (data, index) => double.infinity,
        longPressDuration: const Duration(milliseconds: 200),
        handleBuiltInTouches: false,
        touchCallback: (FlTouchEvent event, LineTouchResponse? response) {
          if (response == null || response.lineBarSpots == null) {
            return;
          }
          // if (event is FlTapUpEvent || event is FlPanUpdateEvent) {
          final spotIndex = response.lineBarSpots!.first.spotIndex;
          setState(() {
            showingTooltipOnSpots.clear();
            showingTooltipOnSpots.add(spotIndex);
          });
          // }
        },
        getTouchedSpotIndicator: (LineChartBarData barData, List<int> spotIndexes) {
          return spotIndexes.map((index) {
            return TouchedSpotIndicatorData(
              FlLine(strokeWidth: 3.w, color: Colors.red),
              FlDotData(
                show: true,
                getDotPainter: (spot, percent, barData, index) => FlDotCirclePainter(
                  radius: 3,
                  color: Colors.red,
                  // color: lerpGradient(
                  //   barData.gradient!.colors,
                  //   barData.gradient!.stops!,
                  //   percent / 100,
                  // ),
                  strokeWidth: 1,
                  strokeColor: Colors.red,
                ),
              ),
            );
          }).toList();
        },
        mouseCursorResolver: (FlTouchEvent event, LineTouchResponse? response) {
          // if (response == null || response.lineBarSpots == null) {
          return SystemMouseCursors.basic;
          // }
          // return SystemMouseCursors.basic;
        },
        touchTooltipData: LineTouchTooltipData(
          tooltipRoundedRadius: 10.r,
          fitInsideVertically: true,
          fitInsideHorizontally: true,
          tooltipBgColor: Colors.grey.withOpacity(.2),
          tooltipPadding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 20.w),
          getTooltipItems: (touchedSpots) {
            LineBarSpot spot = touchedSpots[0];
            HRSummary ss = widget.summaryList[spot.spotIndex];
            return [LineTooltipItem('${ss.tooltipText}', TextStyle(fontSize: 36.sp))];
          },
        ),
      );

  get gridData => FlGridData(
        show: true,
        drawHorizontalLine: false,
        drawVerticalLine: true,
        getDrawingVerticalLine: (value) => FlLine(
          color: ColorConst.secondaryBgColor,
          strokeWidth: 1,
          dashArray: [8, 4],
        ),
      );

  get titlesData => FlTitlesData(
        show: true,
        bottomTitles: AxisTitles(
          sideTitles: SideTitles(
            showTitles: true,
            interval: 1,
            getTitlesWidget: bottomTitleWidgets,
          ),
        ),
        leftTitles: AxisTitles(
          sideTitles: SideTitles(
            showTitles: true,
            getTitlesWidget: leftTitleWidgets,
            reservedSize: 30,
            interval: 1,
          ),
        ),
        topTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
        rightTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
      );

  get borderData => FlBorderData(
        show: true,
        border: Border(
          left: BorderSide(width: 1.w, color: const Color(0xff37434d)),
          bottom: BorderSide(width: 1.w, color: const Color(0xff37434d)),
        ),
      );

  List<FlSpot> getSpotsList() {
    List<FlSpot> items = [];
    int length = widget.summaryList.length;
    for (int i = 0; i < length; i++) {
      items.add(FlSpot(i.toDouble(), widget.summaryList[i].heartRateAvg.toDouble()));
    }
    return items;
  }

  _getLineBarsData() {
    return [
      LineChartBarData(
        showingIndicators: showingTooltipOnSpots,
        spots: getSpotsList(),
        isCurved: false,
        gradient: LinearGradient(
          colors: [
            ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!,
            ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!,
          ],
        ),
        isStrokeCapRound: false,
        dotData: FlDotData(
          show: false,
          getDotPainter: (spot, percent, barData, index) => FlDotCirclePainter(
            radius: 1,
            color: Colors.transparent,
            strokeColor: Colors.red,
          ),
        ),
        belowBarData: BarAreaData(
          show: true,
          gradient: LinearGradient(
            stops: const [0.1, 0.4],
            colors: [
              ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!.withOpacity(0.1),
              ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!.withOpacity(0.1),
            ],
          ),
        ),
      ),
    ];
  }

  Widget bottomTitleWidgets(double value, TitleMeta meta) {
    String text;
    int len = titles.length;
    int idx = value.toInt();

    if (len > 0) {
      if (len == 7) {
        text = idx < len ? titles.elementAt(idx) : '';
      } else {
        if (idx == 0) {
          text = titles.first;
        } else if (idx == len ~/ 2) {
          text = titles.elementAt(len ~/ 2);
        } else if (idx == len - 1) {
          text = titles.last;
        } else {
          text = '';
        }
      }
    } else {
      text = '';
    }

    return SideTitleWidget(
      axisSide: meta.axisSide,
      child: Text(text, style: TextStyle(color: ColorConst.secondaryFontColor, fontSize: 36.sp)),
    );
  }

  Widget leftTitleWidgets(double value, TitleMeta meta) {
    var style = TextStyle(color: ColorConst.secondaryFontColor, fontSize: 36.sp);
    String text;
    switch (value.toInt()) {
      case 1:
        text = '0';
        break;
      case 50:
        text = '50';
        break;
      case 100:
        text = '100';
        break;
      case 150:
        text = '150';
        break;
      case 200:
        text = '200';
        break;
      default:
        return Container();
    }
    return Container(
      width: 100.w,
      padding: EdgeInsets.only(right: 10.w),
      child: Text(text, style: style, textAlign: TextAlign.center),
    );
  }

  /// Lerps between a [LinearGradient] colors, based on [t]
  Color lerpGradient(List<Color> colors, List<double> stops, double t) {
    if (colors.isEmpty) {
      throw ArgumentError('"colors" is empty.');
    } else if (colors.length == 1) {
      return colors[0];
    }

    if (stops.length != colors.length) {
      stops = [];

      /// provided gradientColorStops is invalid and we calculate it here
      colors.asMap().forEach((index, color) {
        final percent = 1.0 / (colors.length - 1);
        stops.add(percent * index);
      });
    }

    for (var s = 0; s < stops.length - 1; s++) {
      final leftStop = stops[s];
      final rightStop = stops[s + 1];
      final leftColor = colors[s];
      final rightColor = colors[s + 1];
      if (t <= leftStop) {
        return leftColor;
      } else if (t < rightStop) {
        final sectionT = (t - leftStop) / (rightStop - leftStop);
        return Color.lerp(leftColor, rightColor, sectionT)!;
      }
    }
    return colors.last;
  }
}
